<?php

namespace Celebrio\Logging;

use Nette\Object;
use Nette\Environment;
use Nette\String;

use LoggerLevel;
use Logger as Log4PHP_Logger;

/**
 * Usage example:
 * \Celebrio\Logging\Logger::getLogger()->debug("test message");
 * \Celebrio\Logging\Logger::getLogger("my_logger")->error("test error", new \Exception("testing exception"));
 *
 * Shorthand usage:
 * \Celebrio\Logging\Logger::debug("shorthand test");
 * \Celebrio\Logging\Logger::error("shorthand error test", new Exception('abc'), "my_logger");
 *
 * @static
 * @author pavel
 */
abstract class Logger extends Object {

    const ERRORS = 'errors';
    const DEBUG_ONLY = 'debug-only';
    const ALL = 'all';
    const TIMER = 'timer';

    private static $initialized = false;
    private static $logDir;

    private static $debug_only_filter = array(
        array(
            'class' => 'LoggerFilterLevelRange',
            'params' => array('levelMax' => 'info')
        )
    );
    private static $error_only_filter = array(
        array(
            'class' => 'LoggerFilterLevelRange',
            'params' => array('levelMin' => 'warn')
        )
    );


    /**
     * Initialization is called right now, after the class definition.
     *
     * @static
     */
    public static function initialize() {
        if (!self::$initialized) {

            self::$logDir = Environment::expand("%logDir%");
            if (!String::endsWith(self::$logDir, "/")) {
                self::$logDir = self::$logDir . "/";
            }

            $config['rootLogger'] = array(
                'level' => LoggerLevel::ALL,
                'appenders' => AZURE
                    ? array('azureAll', 'azureErrors', 'azureDebugOnly')
                    : array('all', 'all_html', 'errors', 'debug-only'),
            );

            $config['loggers'] = array(
                // there are no additional loggers except Timer, root logger takes everything

                self::TIMER => array(
                    'level' => LoggerLevel::ALL,
                    'appenders' => array(AZURE ? 'azureTimer' : self::TIMER),
                    'additivity' => false, // timer logger does not pass the event to the parent logger
                ),
            );

            $config['appenders'] = array(

                self::DEBUG_ONLY => self::getFileAppender(self::DEBUG_ONLY),
                self::ERRORS => self::getFileAppender(self::ERRORS),
                self::ALL => self::getFileAppender(self::ALL),

                'all_html' => array(
                    'class' => 'LoggerAppenderFile',
                    'layout' => array(
                        'class' => 'LoggerLayoutHtml',
                        'params' => array(
                            'locationInfo' => true,
                            "title" => "All events"
                        )
                    ),
                    'params' => array(
                        'file' => self::$logDir . "all.html",
                    )
                ),

                self::TIMER => array(
                    'class' => 'LoggerAppenderFile',
                    'layout' => array(
                        'class' => 'Celebrio\Diagnostics\LoggerLayoutTimer'
                    ),
                    'params' => array(
                        'file' => self::$logDir . self::TIMER . ".log",
                    )
                ),

                // azure appenders

                // this "azureDefault" appender logs only debug messages
                'azureDebugOnly' => array(
                    'class' => 'Celebrio\Diagnostics\LoggerAppenderAzureTable',
                    'params' => array(
                        'table' => "log4phpDebugOnly",
                    ),
                    'filter' => self::$debug_only_filter
                ),
                'azureAll' => array(
                    'class' => 'Celebrio\Diagnostics\LoggerAppenderAzureTable',
                    'params' => array(
                        'table' => "log4phpAll",
                    )
                ),
                'azureErrors' => array(
                    'class' => 'Celebrio\Diagnostics\LoggerAppenderAzureTable',
                    'params' => array(
                        'table' => "log4phpErrors",
                    ),
                    'filter' => self::$error_only_filter
                ),
                'azureTimer' => array(
                    'class' => 'Celebrio\Diagnostics\LoggerAppenderAzureTimer'
                ),
            );

            Log4PHP_Logger::configure($config);

            self::$initialized = true;
        }
    }


    private static function getFileAppender($name) {
        $result = array(
            'class' => 'LoggerAppenderFile',
            'layout' => array(
                'class' => 'LoggerLayoutPattern',
                'params' => array(
                    'conversionPattern' => '%d{D, d M Y H:i:s}§%p§%F§%C§%M§%L§%m%n'
                )
            ),
            'params' => array(
                'file' => self::$logDir . $name . ".log",
            )
        );

        if ($name === self::DEBUG_ONLY) {
            $result['filters'] = self::$debug_only_filter;
        } elseif ($name === self::ERRORS) {
            $result['filters'] = self::$error_only_filter;
        }

        return $result;
    }

    /**
     * Returns configured instance of Logger.
     *
     * @static
     * @param string $logger_name
     * @return \Logger|\LoggerRoot
     */
    public static function getLogger($logger_name = null) {

        // demo logging (to the file)
        if (empty($logger_name)) {
            return Log4PHP_Logger::getRootLogger();
        } else {
            return Log4PHP_Logger::getLogger($logger_name);
        }

    }

    /**
     * This function handles calling "standard" methods of log4php directly. Usage:
     *  \Celebrio\Logging\Logger::debug("shorthand test", new Exception('abc'), "my_logger");
     *
     * This example will call method debug on log4php logger called 'my_logger'. It's the same
     * as if you call this:
     *  \Celebrio\Logging\Logger::getLogger("my_logger")->debug("shorthand test", new Exception('abc'));
     *
     * @static
     * @param string $log_level the method name (should be one of these: trace, debug, info, warn, error, fatal)
     * @param array $args arguments passed to the log4php logger method (see example above)
     *
     * @deprecated
     */
    public static function __callStatic($log_level, $args) {
//        $logger_name = isset($args[2]) ? $args[2] : null;
//        $logger = self::getLogger($logger_name);
//
//        // if args[0] is not string, use var_export to display it
//        if (!is_string($args[0])) {
//            $args[0] = var_export($args[0]);
//        }
//
//        if (method_exists(get_class($logger), $log_level)) {
//            if (isset($args[1]) && $args[1] !== null) {
//                // log message + exception
//                $logger->$log_level($args[0], $args[1]);
//            } else {
//                // no exception given, log only message
//                $logger->$log_level($args[0]);
//            }
//
//        } else {
            parent::__callStatic($log_level, $args);
//        }

    }

}

Logger::initialize();